#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np
import os
import urllib


def loadData():
    """下载数据文件"""
    dataFile = 'iris.data'
    if not os.path.isfile(dataFile):
        urllib.request.urlretrieve(
            'http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',
            dataFile)

    # 使用 numpy.loadtxt 载入数据
    # iris.data 的最后一列是 bytes 类型， 用 converters 参数将其转化为浮点型
    data = np.loadtxt(
        dataFile,
        delimiter=',',
        converters={
            4:
            lambda b: [b'Iris-setosa', b'Iris-versicolor', b'Iris-virginica'].index(b)
        })

    return data


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def gradientDescent(theta, X, y, alpha=1e-3, lparameter=0, maxIter=1000):
    """
    梯度下降实现
    Parameters
    ----------
        X: 包含偏执单元的输入样本矩阵，大小为 m x (n + 1), m 为样本个数， n 为特征个数
        y: 输出样本矩阵, 大小为 m x 1
        alpha: 学习率，梯度下降的速率
        lparameter: 正规化参数
        maxIter: 最大迭代次数
    Returns
    -------
        theta: 待求参数, (number_of_features + 1) x number_of_classes 的矩阵
        J: 损失
    """
    m = y.shape[0]
    nc = y.shape[1]
    J = np.matrix(np.zeros((maxIter, y.shape[1])))
    L = np.matrix(lparameter * np.eye(theta.shape[0]))
    L[0][0] = 0

    for i in range(nc):
        ti = theta[:, i]
        yi = y[:, i]
        counter = 0
        while counter < maxIter:
            s = sigmoid(X * ti)
            ti = ti - alpha * \
                (1 / m * X.transpose() * (s - yi) + L * ti)
            J[counter, i] = -1 / m * (
                yi.transpose() * np.log(s) +
                (1 - yi).transpose() * np.log(1 - s)) + ti.transpose() * L * ti
            counter += 1

        theta[:, i] = ti

    return (theta, J)
